package com.tianji.learning.service.impl;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CategoryBasicDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.*;
import com.tianji.learning.domain.dto.QuestionFormDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.QuestionAdminPageQuery;
import com.tianji.learning.domain.query.QuestionPageQuery;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.enums.QuestionStatus;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.service.IInteractionReplyService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author 丁真
 * @since 2025-07-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {

    private final IInteractionReplyService replyService;
    private final UserClient userClient;
    private final SearchClient searchClient;
    private final CourseClient courseClient;
    private final CatalogueClient catalogueClient;
    private final CategoryCache categoryCache;

    /**
     * 新增互动问题
     *
     * @param formDTO
     */
    @Override
    public void saveQuestion(QuestionFormDTO formDTO) {
        // 1、数据拷贝
        InteractionQuestion question = BeanUtils.toBean(formDTO, InteractionQuestion.class);

        // 2、补充用户ID
        question.setUserId(UserContext.getUser());

        // 3、新增
        boolean save = save(question);
        if (!save) {
            log.error("新增互动问题失败");
        }
    }

    /**
     * 分页查询互动问题
     *
     * @param pageQuery
     * @return
     */
    @Override
    public PageDTO<QuestionVO> pageQuestions(QuestionPageQuery pageQuery) {
        // 1、参数校验，课程ID和小节ID不能同时为空
        if (pageQuery.getCourseId() == null && pageQuery.getSectionId() == null) {
            throw new BadRequestException("课程ID和小节ID不能同时为空");
        }

        // 2、分页查询
        // select * from interaction_question where course_id = ? or section_id = ? and user_id = ? and hidden = 0
        // order by ceate_time desc limit ?,?
        Page<InteractionQuestion> page = lambdaQuery()
                .select(InteractionQuestion.class, tableFieldInfo -> !"description".equals(tableFieldInfo.getColumn()))
                .eq(pageQuery.getCourseId() != null, InteractionQuestion::getCourseId, pageQuery.getCourseId())
                .eq(pageQuery.getSectionId() != null, InteractionQuestion::getSectionId, pageQuery.getSectionId())
                .eq(BooleanUtils.isTrue(pageQuery.getOnlyMine()), InteractionQuestion::getUserId, UserContext.getUser())
                .eq(InteractionQuestion::getHidden, false)
                .page(pageQuery.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        if (ObjectUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }


        // 3、补充信息查询，查询 提问者信息（非匿名的）、查询最近一次回答信息
        // 3.1、收集提问者ID集合、收集最近一次回答ID集合
        Set<Long> userIds = new HashSet<>(records.size());
        Set<Long> lastAnswerIds = new HashSet<>(records.size());
        for (InteractionQuestion record : records) {
            if (!record.getAnonymity()) {
                userIds.add(record.getUserId());
            }
            lastAnswerIds.add(record.getLatestAnswerId());
        }

        // 3.2、根据最近一次回答ID集合进行查询 -> 最近一次回答信息，封装成Map （最近一次回答ID：最近一次回答对象）
        List<InteractionReply> replyList = replyService.listByIds(lastAnswerIds);
        Map<Long, InteractionReply> replyContentMap = new HashMap<>(replyList.size());
        if (ObjectUtils.isNotEmpty(replyList)) {
            for (InteractionReply reply : replyList) {
                replyContentMap.put(reply.getId(), reply);
                if (!reply.getAnonymity()) {
                    userIds.add(reply.getUserId());
                }
            }
        }

        // 3.3、根据提问者ID集合远程调用用户服务 -> 用户信息，封装成Map（用户ID：用户信息）
        Map<Long, UserDTO> userDTOMap = new HashMap<>(userIds.size());
        if (ObjectUtils.isNotEmpty(userIds)) {
            List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
            if (ObjectUtils.isNotEmpty(userDTOS)) {
                userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, Function.identity()));
            }
        }

        // 4、循环遍历分页数据，封装vo集合
        List<QuestionVO> list = new ArrayList<>(records.size());
        for (InteractionQuestion record : records) {
            // 4.1、将po转为vo（拷贝）
            QuestionVO questionVO = BeanUtils.toBean(record, QuestionVO.class);

            // 4.2、补充提问者信息（昵称、头像）
            if (!record.getAnonymity()) {
                questionVO.setUserName(userDTOMap.get(record.getUserId()).getUsername());
                questionVO.setUserIcon(userDTOMap.get(record.getUserId()).getIcon());
            }

            // 4.3、补充最近一次回答信息（回答内容、回答者昵称）
            InteractionReply interactionReply = replyContentMap.get(record.getLatestAnswerId());
            if (ObjectUtils.isNotEmpty(interactionReply)) {
                questionVO.setLatestReplyContent(interactionReply.getContent());
                if (!record.getAnonymity()) {
                    UserDTO userDTO = userDTOMap.get(interactionReply.getUserId());
                    if (ObjectUtils.isNotEmpty(userDTO)) {
                        questionVO.setLatestReplyUser(userDTO.getUsername());
                    }
                }
            }

            // 4.4、添加vo到集合
            list.add(questionVO);

        }

        // 5、封装分页结果返回

        return PageDTO.of(page, list);
    }

    /**
     * 用户端根据id查询问题详情
     *
     * @param id
     * @return
     */
    @Override
    public QuestionVO queryQuestionById(Long id) {
        // 1、根据ID查询问题
        InteractionQuestion question = getById(id);
        if (ObjectUtils.isEmpty(question) || question.getHidden()) {
            log.error("用户端根据id查询问题详情失败：{}", id);
            return null;
        }

        // 2、查询提问者信息
        UserDTO userDTO = new UserDTO();
        if (!question.getAnonymity()) {
            userDTO = userClient.queryUserById(question.getUserId());
        }

        // 3、封装vO返回
        QuestionVO questionVO = BeanUtils.toBean(question, QuestionVO.class);
        if (!question.getAnonymity()) {
            questionVO.setUserName(userDTO.getUsername());
            questionVO.setUserIcon(userDTO.getIcon());
        }

        return questionVO;
    }

    /**
     * 管理员端-分页查询问题
     *
     * @param pageQuery
     * @return
     */
    @Override
    public PageDTO<QuestionAdminVO> pageAdminQuestions(QuestionAdminPageQuery pageQuery) {
        // 1、调用ES处理课程名称，得到课程ID集合
        List<Long> coursesIds = null;
        if (ObjectUtil.isNotEmpty(pageQuery.getCourseName())) {
            coursesIds = searchClient.queryCoursesIdByName(pageQuery.getCourseName());
            if (ObjectUtil.isEmpty(coursesIds)) {
                return PageDTO.empty(0L, 0L);
            }
        }
        // 2、分页查询问题列表
        // select * from interaction_question where course_id in () and status = ? and create_time >= ? and create_time <= ?
        // order by create_time desc limit ?,?
        Page<InteractionQuestion> page = lambdaQuery()
                .in(ObjectUtils.isNotEmpty(coursesIds), InteractionQuestion::getCourseId, coursesIds)
                .eq(pageQuery.getStatus() != null, InteractionQuestion::getStatus, pageQuery.getStatus())
                .ge(pageQuery.getBeginTime() != null, InteractionQuestion::getCreateTime, pageQuery.getBeginTime())
                .le(pageQuery.getEndTime() != null, InteractionQuestion::getCreateTime, pageQuery.getEndTime())
                .page(pageQuery.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        if (ObjectUtils.isEmpty(records)) {
            log.error("管理员端-分页查询问题失败：{}", pageQuery);
            return PageDTO.empty(page);
        }

        // 3、补充信息查询（章节数据、课程数据、用户数据）
        // 3.0、收集各种业务ID
        Set<Long> userIds = new HashSet<>(records.size());// 用户ID
        Set<Long> chapterIds = new HashSet<>(records.size());// 章节ID
        Set<Long> courseIds = new HashSet<>(records.size());// 课程ID
        for (InteractionQuestion record : records) {
            userIds.add(record.getUserId());
            courseIds.add(record.getCourseId());
            chapterIds.add(record.getChapterId());
            chapterIds.add(record.getSectionId());
        }

        // 3.1、根据用户ID集合查询用户信息
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        Map<Long, String> userDTOMap = new HashMap<>(userIds.size());
        if (ObjectUtils.isNotEmpty(userDTOS)) {
            userDTOMap = CollStreamUtil.toMap(userDTOS, UserDTO::getId, UserDTO::getUsername);
        }

        // 3.2、根据课程ID集合查询课程信息
        List<CourseSimpleInfoDTO> courseInfos = courseClient.getSimpleInfoList(courseIds);
        Map<Long, CourseSimpleInfoDTO> courseInfoMap = new HashMap<>(courseIds.size());
        if (ObjectUtils.isNotEmpty(courseInfos)) {
            courseInfoMap = CollStreamUtil.toMap(courseInfos, CourseSimpleInfoDTO::getId, Function.identity());
        }

        // 3.3、根据章节ID集合查询章节信息
        List<CataSimpleInfoDTO> cataInfos = catalogueClient.batchQueryCatalogue(chapterIds);
        Map<Long, String> cataInfoMap = new HashMap<>(chapterIds.size());
        if (ObjectUtils.isNotEmpty(cataInfos)) {
            cataInfoMap = CollStreamUtil.toMap(cataInfos, CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName);
        }

        // 4、循环列表，填充各种数据
        List<QuestionAdminVO> voList = new ArrayList<>(records.size());
        for (InteractionQuestion record : records) {
            // 4.1、属性拷贝 po -> vo
            QuestionAdminVO questionAdminVO = BeanUtils.toBean(record, QuestionAdminVO.class);

            // 4.2、填充章节名称
            questionAdminVO.setChapterName(cataInfoMap.getOrDefault(record.getChapterId(), ""));
            questionAdminVO.setSectionName(cataInfoMap.getOrDefault(record.getSectionId(), ""));

            // 4.3、填充提问者昵称
            questionAdminVO.setUserName(userDTOMap.getOrDefault(record.getUserId(), ""));

            // 4.4、填充课程名称 和 三级分类信息
            CourseSimpleInfoDTO courseInfoDTO = courseInfoMap.get(record.getCourseId());
            if (ObjectUtils.isNotEmpty(courseInfoDTO)) {
                questionAdminVO.setCourseName(courseInfoDTO.getName());

                // 课程分类：已知三级分类ID -> 三级分类名称拼接的字符串   （一级分类/二级分类/三级分类）
                questionAdminVO.setCategoryName(categoryCache.getCategoryNames(courseInfoDTO.getCategoryIds()));
            }
            // 4.5、添加vo到集合
            voList.add(questionAdminVO);

        }
        // 5、封装分页数据并返回

        return PageDTO.of(page, voList);
    }

    /**
     * 编辑互动问题接口
     *
     * @param id
     * @param formDTO
     */
    @Override
    public void updateQuestion(Long id, QuestionFormDTO formDTO) {
        // 参数复制
        InteractionQuestion question = BeanUtils.toBean(formDTO, InteractionQuestion.class);

        // 补充缺失的数据
        question.setId(id);

        // 修改问题
        boolean update = updateById(question);
        if (!update) {
            log.error("更新问题失败：{}", question);
        }
    }

    /**
     * 管理端-根据id查询问题详情
     *
     * @param id
     * @return
     */
    @Override
    public QuestionAdminVO queryQuestionInfoById(Long id) {
        // 1.根据ID查询问题
        InteractionQuestion question = getById(id);
        if (ObjectUtils.isEmpty(question)) {
            throw new BadRequestException("问题不存在");
        }

        // 2.查询用户信息
        UserDTO userDTO = userClient.queryUserById(question.getUserId());
        if (ObjectUtils.isEmpty(userDTO)) {
            log.error("查询用户信息失败：{}", question.getUserId());
        }

        // 3.查询课程信息
        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(question.getCourseId(), true, true);
        if (ObjectUtils.isEmpty(courseInfo)) {
            log.error("查询课程信息失败：{}", question.getCourseId());
        }
        List<Long> teacherIds = courseInfo.getTeacherIds();
        List<UserDTO> teacherDTOS = userClient.queryUserByIds(teacherIds);
        // 3.1. 拼接老师姓名字符串
        String teacherNames = teacherDTOS.stream().map(UserDTO::getName).collect(Collectors.joining("/"));

        // 4.查询章节信息
        List<CataSimpleInfoDTO> catalogue = catalogueClient.batchQueryCatalogue(Arrays.asList(question.getChapterId(), question.getSectionId()));
        Map<Long, String> cataInfoMap = new HashMap<>(catalogue.size());
        if (ObjectUtils.isNotEmpty(catalogue)) {
            cataInfoMap = CollStreamUtil.toMap(catalogue, CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName);
        }

        // 5.计算回答数量
        int count = replyService.count(
                Wrappers.lambdaQuery(InteractionReply.class)
                        .eq(InteractionReply::getQuestionId, id)
                        .eq(InteractionReply::getAnswerId, 0)
                        .ne(InteractionReply::getHidden, false)
        );

        // 6.填充各种数据
        QuestionAdminVO questionAdminVO = QuestionAdminVO.builder()
                .title(question.getTitle())
                .description(question.getDescription())
                .answerTimes(count)
                .createTime(question.getCreateTime())
                .hidden(question.getHidden())
                .userName(userDTO.getUsername())
                .userIcon(userDTO.getIcon())
                .courseName(courseInfo.getName())
                .teacherName(teacherNames)
                .chapterName(cataInfoMap.get(question.getChapterId()))
                .sectionName(cataInfoMap.get(question.getSectionId()))
                .categoryName(categoryCache.getCategoryNames(courseInfo.getCategoryIds()))
                .build();

        // 7. 修改问题状态为已查看
        boolean update = lambdaUpdate()
                .set(QuestionStatus.UN_CHECK.equals(question.getStatus()), InteractionQuestion::getStatus, QuestionStatus.CHECKED)
                .eq(InteractionQuestion::getId, id)
                .update();
        if (!update) {
            log.error("修改问题状态失败：{}", id);
        }

        return questionAdminVO;
    }

    /**
     * 管理端-隐藏或显示问题
     *
     * @param id
     * @param hidden
     */
    @Override
    public void updateQuestionHidden(Long id, Boolean hidden) {
        //
        boolean update = lambdaUpdate()
                .set(InteractionQuestion::getHidden, hidden)
                .eq(InteractionQuestion::getId, id)
                .update();
        if (!update) {
            log.error("修改问题隐藏状态失败：{}", id);
        }

    }

    /**
     * 删除我的问题
     *
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteMyQuestion(Long id) {
        // 1. 查询问题是否存在
        InteractionQuestion question = getById(id);
        if (question == null) {
            throw new BadRequestException("问题不存在");
        }

        // 2. 判断是否是当前用户提问的
        Long userId = UserContext.getUser();
        if (!userId.equals(question.getUserId())) {
            throw new BadRequestException("不能删除其他用户问题");
        }

        // 3. 删除问题下的回答及评论
        replyService.remove(
                Wrappers.lambdaQuery(InteractionReply.class)
                        .eq(InteractionReply::getQuestionId, id)
        );

        // 4. 删除问题
        removeById(id);
    }
}
